home *** CD-ROM | disk | FTP | other *** search
- /* $Header: log.c,v 2.3 90/05/03 10:13:31 chip Exp $
- *
- * Deliver logging.
- *
- * $Log: log.c,v $
- * Revision 2.3 90/05/03 10:13:31 chip
- * Print correct filename when log can't be opened.
- *
- * Revision 2.2 90/03/05 17:54:53 chip
- * Create log.c from various routines throughout the code.
- *
- */
-
- #include "deliver.h"
- #include <time.h>
-
- /*----------------------------------------------------------------------
- * Open temporary log files.
- */
-
- openlogs()
- {
- #ifdef ERRLOG
- /* If we're delivering and not being verbose, keep an error log. */
-
- if (!dryrun && !verbose)
- {
- errlogfile = tempfile();
- if ((errlog = ftcreate(errlogfile)) == NULL)
- syserr("can't create %s", errlogfile);
- }
- #endif
-
- #ifdef LOG
- /* If we're delivering and the log file exists, keep data for it. */
-
- if (!dryrun && exists(LOG))
- {
- logfile = tempfile();
- if ((log = ftcreate(logfile)) == NULL)
- syserr("can't create %s", logfile);
- }
- #endif
- }
-
- /*------------------------------------------------------------------------
- * Discard temporary log files.
- */
-
- tosslogs()
- {
- if (logfile && unlink(logfile) == -1)
- (void) syserr("can't remove %s", logfile);
- if (errlogfile && unlink(errlogfile) == -1)
- (void) syserr("can't remove %s", logfile);
- }
-
- /*----------------------------------------------------------------------
- * Write a report to the log file.
- */
-
- logreport(ac, av)
- int ac;
- char **av;
- {
- int a;
-
- if (!log)
- return;
-
- logstart(log);
-
- if (sender && *sender)
- (void) fprintf(log, "sender: %s\n", sender);
- if (boxdelivery)
- (void) fprintf(log, "mailbox%s:", (ac > 1) ? "es" : "");
- else
- (void) fprintf(log, "destination%s:", (ac > 1) ? "s" : "");
- for (a = 0; a < ac; ++a)
- (void) fprintf(log, " \"%s\"", av[a]);
- (void) fputc('\n', log);
-
- logstate("delivered", ST_DONE);
- logstate("failed", ST_ERROR);
-
- logdone(log);
- }
-
- /*----------------------------------------------------------------------
- * Log the destinations with the given state.
- * If any are found, the list is prefixed with the given description.
- */
-
- logstate(desc, state)
- char *desc;
- DSTATE state;
- {
- DEST *d;
- int dcount;
-
- dcount = 0;
- for (d = first_dest(); d; d = next_dest(d))
- {
- if (d->d_state != state)
- continue;
-
- if (++dcount == 1)
- (void) fprintf(log, "%s:", desc);
- (void) fprintf(log, " %s", d->d_name);
- if (d->d_class == CL_MBOX)
- (void) fprintf(log, ":%s", d->d_param);
- else if (d->d_class == CL_PROG)
- (void) fprintf(log, "|\"%s\"", d->d_param);
- }
- if (dcount)
- (void) fputc('\n', log);
- }
-
- /*----------------------------------------------------------------------
- * Save contents of temporary logs in the real logfiles.
- */
-
- savelogs()
- {
- /* If logs weren't kept, forget it. */
-
- if (!log && !errlog)
- return;
-
- /* If temporary logs contain anything, append them to real logs. */
-
- if ((log && ftell(log) > 0)
- || (errlog && ftell(errlog) > 0))
- {
- if (create_lockfile(LOGLOCK) == 0)
- {
- #ifdef LOG
- applog(&log, LOG);
- #endif
- errdone();
- #ifdef ERRLOG
- applog(&errlog, ERRLOG);
- #endif
- (void) remove_lockfile(LOGLOCK);
- }
- }
- }
-
- /*----------------------------------------------------------------------
- * Append a temporary log file to a real logfile.
- * We pass a FILE **, so that it can be set to NULL when closed;
- * this is important, since errlog is used by syserr().
- * Note: The logfile is ass_u_med to be locked already!
- */
-
- applog(fpp, realfile)
- FILE **fpp;
- char *realfile;
- {
- FILE *fp = fpp ? *fpp : NULL;
- int fd, realfd;
-
- /* If log data weren't kept, never mind. */
-
- if (fp == NULL)
- return;
-
- /* Flush buffered data. */
-
- (void) fflush(fp);
-
- /* If the file is empty, never mind. */
-
- if (ftell(fp) == 0)
- {
- (void) fclose(fp);
- *fpp = NULL;
- return;
- }
-
- /* Get an fd and close the stream. */
-
- if ((fd = dup(fileno(fp))) == -1)
- {
- syserr("can't dup log fd");
- (void) fclose(fp);
- *fpp = NULL;
- return;
- }
- (void) fclose(fp);
- *fpp = NULL;
-
- /*
- * Open the real logfile, creating it if necessary.
- * Note that there is no race condition since the logs are locked.
- */
-
- #ifdef O_CREAT
- realfd = open(realfile, O_WRONLY|O_CREAT, 0666);
- #else
- if ((realfd = open(realfile, O_WRONLY)) == -1)
- realfd = creat(realfile, 0666);
- #endif
- if (realfd == -1)
- syserr("can't open %s for writing", realfile);
- else
- {
- /* Append the temporary log to the real log. */
-
- (void) lseek(fd, 0L, 0);
- (void) lseek(realfd, 0L, 2);
- (void) copyfd(fd, realfd);
- (void) close(realfd);
- }
-
- /* Close the temporary log. */
-
- (void) close(fd);
- }
-
- /*----------------------------------------------------------------------
- * Record any interesting information in the error log file.
- */
-
- errinfo()
- {
- if (!errlog)
- return;
-
- /* Log undelivered mail. */
-
- errundel();
-
- /* If any errors have been logged, record the failed header. */
-
- if (ftell(errlog) > 0)
- errheader();
- }
-
- /*----------------------------------------------------------------------
- * Log undelivered mail.
- *
- * Note that this algorithm assumes that delivery to the MBX_UNDEL mailbox
- * is always worth reporting.
- */
-
- errundel()
- {
- DEST *d;
-
- if (!errlog)
- return;
-
- for (d = first_dest(); d; d = next_dest(d))
- {
- if (d->d_state == ST_DONE
- && d->d_class == CL_MBOX
- && strcmp(d->d_param, MBX_UNDEL) == 0)
- {
- CONTEXT *ct;
- char *home;
-
- if ((ct = name_context(d->d_name)) != NULL)
- home = ct->ct_home;
- else
- home = "~"; /* should never happen */
-
- errstart();
- (void) fprintf(errlog,
- "Undelivered mail for %s put in %s/%s\n",
- d->d_name, home, MBX_UNDEL);
- }
- }
- }
-
- /*----------------------------------------------------------------------
- * Log the message header.
- */
-
- errheader()
- {
- FILE *hfp;
- int hfd;
-
- if (!errlog)
- return;
-
- /* Copy the failed message's header. */
-
- hfd = dup(tfd[T_HDR]);
- hfp = (hfd < 0) ? NULL : fdopen(hfd, "r");
- if (hfp == NULL)
- {
- (void) fprintf(errlog, "%s: can't open header file %s\n",
- progname, tfile[T_HDR]);
- }
- else
- {
- int c, oc;
-
- (void) fprintf(errlog, "+ Header:\n");
-
- (void) fseek(hfp, 0L, 0);
- oc = '\n';
- while ((c = getc(hfp)) != EOF)
- {
- if (oc != '\n' || c != '\n')
- {
- if (oc == '\n')
- (void) fputs("| ", errlog);
- (void) putc(c, errlog);
- }
- oc = c;
- }
-
- (void) fclose(hfp);
- }
- }
-
- /*----------------------------------------------------------------------
- * Record a time stamp in the error log file.
- */
-
- errstart()
- {
- /* If we've already written a time stamp, don't do it again. */
-
- if (!errlog || ftell(errlog) > 0)
- return;
-
- /* Write a time stamp and various useful info. */
-
- logstart(errlog);
- (void) fprintf(errlog, "process %d", getpid());
- if (rec_parent > 0)
- (void) fprintf(errlog, ", parent %d", rec_parent);
- (void) fprintf(errlog, ": %s %s\n", progname, version);
- }
-
- /*----------------------------------------------------------------------
- * Record the end of this process's error log entry.
- */
-
- errdone()
- {
- /* If we never wrote to the error log file, do nothing. */
-
- if (!errlog || ftell(errlog) == 0)
- return;
-
- /* Write a simple closing line for the error log entry. */
-
- (void) fprintf(errlog, "process %d", getpid());
- if (rec_parent > 0)
- (void) fprintf(errlog, ", parent %d", rec_parent);
- (void) fprintf(errlog, ": exit\n");
-
- logdone(errlog);
- }
-
- /*----------------------------------------------------------------------
- * Start a log entry.
- * Various useful info goes here -- especially a timestamp.
- */
-
- logstart(fp)
- FILE *fp;
- {
- struct tm *lt;
- time_t now;
- static char month[12][4] = {
- "Jan", "Feb", "Mar", "Apr", "May", "Jun",
- "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
- };
-
- (void) time(&now);
- lt = localtime(&now);
-
- (void) fputc('\n', fp);
- if (rec_level)
- (void) fprintf(fp, "[%d]", rec_level);
- else
- (void) fputs("---", fp);
- (void) fputs("------------------------ ", fp);
- (void) fprintf(fp, "%d %s %d, %02d:%02d:%02d %s\n",
- lt->tm_mday, month[lt->tm_mon], lt->tm_year + 1900,
- lt->tm_hour, lt->tm_min, lt->tm_sec,
- #ifdef USG
- tzname[lt->tm_isdst ? 1 : 0]
- #else
- lt->tm_zone
- #endif
- );
- }
-
- /*----------------------------------------------------------------------
- * Write a concluding marker to the given logfile.
- * This marker separates instances of Deliver at recursion level zero.
- */
-
- logdone(fp)
- FILE *fp;
- {
- if (rec_level == 0)
- (void) fputs("===========================\n\n", fp);
- }
-